<?php


namespace models\Business;


use models\Exception\Business\OauthException;
use Yaf\Registry;
use Yaf\Session;
use youliPhpLib\Common\RequestHelper;
use youliPhpLib\Common\StringOperation;
use Yurun\OAuthLogin\QQ\OAuth2 as QQOauth;
use Yurun\OAuthLogin\Weixin\OAuth2 as WeChatOauth;

class TencentOauth
{

//    const WECHAT_APP_ID = 'wx77a1bb7cadfc17c5';
//    const WECHAT_APP_KEY = 'bbdea7aa7a255ec522512b19948ae901';

    // 在微信公众号平台获取
    const WECHAT_APP_ID = 'wxcb09ae5b3eaf1dfe';
    const WECHAT_APP_KEY = '935ff9903b90f8b5bfa5f497b095aaa2';
    const WECHAT_CALLBACK_URL = 'https://api.douziyoupin.com/callback/wechat/oauth';

    // 微信公众号分享 获取access_token
    const WECHAT_GET_ACCESS_TOKEN_URL = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=#APP_ID#&secret=#APP_SECRET#';
    // 微信公众号分享 获取jsapi_ticket
    const WECHAT_GET_ACCESS_JSAPI_TICKET_URL = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=#ACCESS_TOKEN#&type=jsapi';

    static public function getWeChatJsApiParam() {
    }

    static public function genWeChatJsApiSignature($url = '') {
        // 根据签名规则，判断url是否合法
        $signature_url = ! empty($url) ? $url : '';
        if (empty($signature_url))
            throw new OauthException("生成jsapi所需签名的url不能为空", 400);
        $signature_url = strpos($signature_url, '#') !== false ? substr($signature_url, 0, strpos($url, '#')) : $signature_url;

        // 判断access_token是否存在于redis
        $redis = Registry::get('redis');
        try {
            $redis->ping();
        } catch (\Exception $e) {
            $redis->auth(Registry::get('config')['redis']['master']['auth']);
        }

        $redis->select(Registry::get('config')['redis']['string']['db']);
        // 判断access_token不存在于redis或access_token过期
        $key = "wechat_jsapi_ticket_access_token";
        $jsapi_ticket = false;
        if (false !== $jsapi_ticket_str = $redis->get($key)) {
            $jsapi_ticket_arr = json_decode($jsapi_ticket_str, true);
            if ($jsapi_ticket_arr['expire'] >= time())
                $jsapi_ticket = $jsapi_ticket_arr['jsapi_ticket'];
        }

        // access_token不存在或access_token过期了
        // 调用接口获取access_token
        if ($jsapi_ticket === false) {
            $url = str_replace(['#APP_ID#', '#APP_SECRET#'],
                [self::WECHAT_APP_ID, self::WECHAT_APP_KEY],
                self::WECHAT_GET_ACCESS_TOKEN_URL);
            list($header_size, $body) = RequestHelper::curlRequest($url, '', 'GET');
            $access_token = json_decode($body, true);
            // access_token接口调用失败
            if ($access_token['errcode'] !== 0 && isset($access_token['errmsg']))
                throw new OauthException($access_token['errmsg'], 400);

            // 调用获取jsapi_ticket接口
            $access_token_url = str_replace('#ACCESS_TOKEN#', $access_token['access_token'], self::WECHAT_GET_ACCESS_JSAPI_TICKET_URL);
            list($header_size, $body) = RequestHelper::curlRequest($access_token_url, '', 'GET');
            $jsapi_ticket = json_decode($body, true);
            // jsapi_ticket接口调用失败
            if (! isset($jsapi_ticket['ticket']) || ! isset($jsapi_ticket['errcode']) || $jsapi_ticket['errcode'] !=0 )
                throw new OauthException("jsapi_ticket获取失败", 400);

            $jsapi_ticket = $jsapi_ticket['ticket'];
            $redis->set($key, json_encode(['jsapi_ticket' => $jsapi_ticket, 'expire' => time() + $access_token['expires_in']]));
        }

        // 生成签名
        // 规则：
        //参与签名的字段包括noncestr（随机字符串）, 有效的jsapi_ticket, timestamp（时间戳）, url（当前网页的URL，不包含#及其后面部分）。
        // 对所有待签名参数按照字段名的ASCII 码从小到大排序（字典序）后，使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串string1。
        // 这里需要注意的是所有参数名均为小写字符。对string1作sha1加密，字段名和字段值都采用原始值，不进行URL 转义。
        // 参考链接：https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62
        $param = [
            'jsapi_ticket' => $jsapi_ticket,
            'url' => $signature_url,
            'nonceStr' => StringOperation::getRandStr('letter', 16),
            'timestamp' => time(),
        ];
        ksort($param);
        $original_string = urldecode(http_build_query($param));
        $signature = sha1($original_string);

        return [$original_string, $signature];
    }

    /**
     * 获取微信oauth的url
     * @return string
     */
    static public function weChatLogin() {
        $qq_oauth = new WeChatOauth(self::WECHAT_APP_ID, self::WECHAT_APP_KEY, self::WECHAT_CALLBACK_URL);
//        $url = $qq_oauth->getUrl();
        $url = $qq_oauth->getWeixinAuthUrl();
        Session::getInstance()->set('YL_WECHAT_STATE', $qq_oauth->state);
        return $url;
    }

    /**
     * 通过callback的state，获取用户信息
     * @param $state
     * @return array
     * @throws OauthException
     * @throws \Yurun\OAuthLogin\ApiException
     */
    static public function getWeChatUserInfo($state) {
        // 判断微信服务器发来的state参数值与session中的state是否一致
        if (Session::getInstance()->get('YL_WECHAT_STATE') != $state) {
            $redis = Registry::get('redis');
            $redis->auth(Registry::get('config')['redis']['master']['auth']);
            $redis->select(9);
            if (false === $redis->exists($state))
                throw new OauthException('请求参数中的state与session中的state不一致', 400);
        }

        // 测试用 测试时，注释掉44，46，48行代码
//        $user_info = '{"openid":"oEJvnvp4Rn8JTh3SrNO1vpK9kocg","nickname":"\u5899\u58c1\u4e0d\u8981\u5237\u767d\u8272","sex":1,"language":"zh_CN","city":"\u53a6\u95e8","province":"\u798f\u5efa","country":"\u4e2d\u56fd","headimgurl":"http:\/\/thirdwx.qlogo.cn\/mmopen\/vi_32\/DYAIOgq83eooonjhIsfOIr4rniaap3FSoUNNWKrNdw1oppsEsibO5feOiamicPj71U213MHJUa9VzslkQtQ1yibRyRg\/132","privilege":[],"unionid":"o3H7qwdKqnKycNlRULSSkj5B5xXo"}';
//        $user_info = json_decode($user_info, true);
        // 实例化微信第三方登陆sdk
        $WeChat_oauth = new WeChatOauth(self::WECHAT_APP_ID, self::WECHAT_APP_KEY, self::WECHAT_CALLBACK_URL);
        // 通过state获取access_token
        $WeChat_oauth->getAccessToken($state);
        // 通过access_token拉去用户信息
        $user_info = $WeChat_oauth->getUserInfo();

        return [
            'open_id' => $user_info['openid'],
            'union_id' => $user_info['unionid'] ? $user_info['unionid'] : $user_info['openid'],
            'avatar' => $user_info['headimgurl'],
            'country' => $user_info['country'] ? $user_info['country'] : '中国',
            'province' => $user_info['province'] ? $user_info['province'] : '0',
            'city' => $user_info['city'] ? $user_info['city'] : '0',
            'nickname' => $user_info['nickname'],
            'sex' => $user_info['sex'],
            'type' => 2
        ];
    }

    const QQ_APP_ID = '101870937';
    const QQ_APP_KEY = '1be6c802931d025d7277b309bfae8ae2';
    const QQ_CALLBACK_URL = 'https://api.douziyoupin.com/callback/qq/oauth';

    /**
     * 获取qq oauth的url
     * @return string
     */
    static public function qqLogin() {
        $qq_oauth = new QQOauth(self::QQ_APP_ID, self::QQ_APP_KEY, self::QQ_CALLBACK_URL);
        $url = $qq_oauth->getAuthUrl();
        Session::getInstance()->set('YL_QQ_STATE', $qq_oauth->state);

        return $url;
    }

    /**
     * 通过callback的state参数获取open_id及用户信息
     * @param $state
     * @return array
     * @throws OauthException
     * @throws \Yurun\OAuthLogin\ApiException
     */
    static public function qqGetUserInfo($state) {
        // 判断微信服务器发来的state参数值与session中的state是否一致
        if (Session::getInstance()->get('YL_QQ_STATE') != $state) {
            $redis = Registry::get('redis');
            $redis->auth(Registry::get('config')['redis']['master']['auth']);
            $redis->select(9);
            if (false === $redis->exists($state))
                throw new OauthException('请求参数中的state与session中的state不一致', 400);
        }

        $qq_oauth = new QQOauth(self::QQ_APP_ID, self::QQ_APP_KEY, self::QQ_CALLBACK_URL);

        // 测试专用，测试时，注释掉 97，99，101行的代码
//        $open_id = '3A46C2DE9357286417C03AA58DC25A1A';
//        $user_info = '{"ret":0,"msg":"","is_lost":0,"nickname":"\u6572\u5c3c\u739b","gender":"\u7537","gender_type":2,"province":"","city":"","year":"0","constellation":"","figureurl":"http:\/\/qzapp.qlogo.cn\/qzapp\/101870937\/3A46C2DE9357286417C03AA58DC25A1A\/30","figureurl_1":"http:\/\/qzapp.qlogo.cn\/qzapp\/101870937\/3A46C2DE9357286417C03AA58DC25A1A\/50","figureurl_2":"http:\/\/qzapp.qlogo.cn\/qzapp\/101870937\/3A46C2DE9357286417C03AA58DC25A1A\/100","figureurl_qq_1":"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=jkTjY0zaUJHKYBXYViaGEvA&s=40","figureurl_qq_2":"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=jkTjY0zaUJHKYBXYViaGEvA&s=100","figureurl_qq":"http:\/\/thirdqq.qlogo.cn\/g?b=oidb&k=jkTjY0zaUJHKYBXYViaGEvA&s=100","figureurl_type":"0","is_yellow_vip":"0","vip":"0","yellow_vip_level":"0","level":"0","is_yellow_year_vip":"0"}';
//        $user_info = json_decode($user_info, true);
        // 通过state获取access_token
        $qq_oauth->getAccessToken($state);
        // 获取open_id
        $open_id = $qq_oauth->getOpenID();
        // 通过access_token拉去用户信息
        $user_info = $qq_oauth->getUserInfo();

        return [
            'open_id' => $open_id,
            'union_id' => '',
            'avatar' => $user_info['figureurl'],
            'country' => $user_info['country'] ? $user_info['country'] : '',
            'province' => $user_info['province'] ? $user_info['province'] : '0',
            'city' => $user_info['city'] ? $user_info['city'] : '0',
            'nickname' => $user_info['nickname'],
            'sex' => $user_info['gender_type'] == 2 ? 1 : 0,
            'type' => 3
        ];
    }

}
